package cn.dengta.webapp.user.entity;

import java.util.*;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import cn.dengta.common.model.*;
import cn.dengta.context.model.MessagerStatus;
import cn.dengta.context.model.WesKit;
import cn.dengta.webapp.base.entity.TimeBasedEntity;
import cn.dengta.webapp.user.cache.Industry;
import cn.dengta.webapp.user.model.*;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.annotation.JSONField;
import com.alibaba.fastjson.annotation.JSONType;
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.serializer.ValueFilter;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Getter;
import lombok.Setter;
import lombok.experimental.Accessors;
import me.codeplayer.util.*;
import org.springframework.cglib.beans.BeanMap;

/**
 * @author lgy
 * @since 2022-02-26
 */
@Getter
@Setter
@Accessors(chain = true)
@TableName(value = "dt_user_info", autoResultMap = true)
@JSONType(ignores = { "addTime", "updateTime" })
public class UserInfo extends TimeBasedEntity {

	private static final long serialVersionUID = 1L;

	/** 群 VIP 配置 */
	public static final String EXTEND_FIELD = "group_vip";

	/** 用户ID */
	private Long userId;
	/** 所在 省 市 区 */
	private String location;
	/** 详细地址 */
	private String addr;
	/** 职业 */
	private String job;
	/** 感情状态 0-单身，1-恋爱中，2-已婚，3-开放式，4-保密 */
	private MaritalStatus maritalStatus;
	/** 交友宣言 */
	private String slogan;
	/** 注册来源 */
	private Integer sourceType;
	/** 备注 */
	private String remark;
	/** 通知配置 {@link NoticeConfig} */
	private String noticeConfig;
	/** 个性化开关配置 {@link SwitchConfig} */
	private String switchConfig;
	/** 关注在线通知提醒 */
	private Integer likeOnlineNotice;

	/** 群VIP等级 1=VIP; 2=SVIP; 3=SSVIP; 4=SUPERVIP; 5=TOPVIP */
	private Integer groupVipLevel;
	/** 群VIP过期时间 */
	private Date groupVipExpireTime;
	/** 扩展字段 */
	private String extend;
	/** 家乡 省 市 区 0=未知 */
	private Long homeTown;
	/** 身高 如：172 CM */
	private Integer height;
	/** 体重 如： 80 KG */
	private Integer weight;
	/** 学历 */
	private Education education;
	/** 年收入 @sess YearIncomeType */
	private Integer yearIncome;
	/** 行业 编码 参考 @see Industry */
	private Integer industry;
	/** 交友目的 @see FindTagType */
	private Integer findTag;

	private transient JSONObject extendObj;
	private transient NoticeConfig noticeCfg;
	private transient SwitchConfig switchCfg;
	protected transient String province, city, area;
	private transient GroupVipRule groupVipRule;
	/** 基本资料完善需要全部完善的字段集合 */
	private static final Set<String> info_flag = new HashSet<>();

	static {
		info_flag.add("height");
		info_flag.add("weight");
		info_flag.add("education");
		info_flag.add("yearIncome");
		info_flag.add("industry");
		info_flag.add("findTag");
	}

	/***
	 * 是否已完善基本资料
	 */
	public static final boolean isPerfectInfo(UserInfo userInfo) {
		BeanMap map = BeanMap.create(userInfo);
		for (String s : info_flag) {
			if (map.get(s) == null) {
				return false;
			}
		}
		return true;
	}

	public UserInfo init(final UserInfo input, Date now) {
		this.userId = X.expectNotNull(userId, input.userId);
		this.location = X.expectNotNull(input.location, location, "");
		this.addr = X.expectNotNull(input.addr, addr, "");
		this.job = X.expectNotNull(input.job, job, "");
		this.maritalStatus = X.expectNotNull(input.maritalStatus, maritalStatus);
		this.slogan = StringUtil.toString(slogan);
		this.remark = X.expectNotNull(input.remark, remark, "");
		this.height = X.expectNotNull(input.height, this.height);
		this.weight = X.expectNotNull(input.weight, this.weight);
		this.education = X.expectNotNull(input.education, this.education);
		this.yearIncome = X.expectNotNull(input.yearIncome, this.yearIncome);
		this.industry = X.expectNotNull(input.industry, this.industry);
		this.findTag = X.expectNotNull(input.findTag, this.findTag);
		this.homeTown = X.expectNotNull(input.homeTown, this.homeTown);
		super.initTime(now);
		return this;
	}

	public void setNoticeCfg(NoticeConfig cfg) {
		this.noticeCfg = cfg;
		this.noticeConfig = cfg == null ? "" : JSONUtil.encode(cfg);
	}

	public NoticeConfig getNoticeCfg() {
		NoticeConfig cfg = noticeCfg;
		if (cfg == null && StringUtil.notEmpty(this.noticeConfig)) {
			noticeCfg = cfg = JSONUtil.parseObject(this.noticeConfig, NoticeConfig.class);
		}
		return cfg;
	}

	@JSONField(serialize = false)
	@Nonnull
	public NoticeConfig getNoticeCfgOrDefault() {
		NoticeConfig cfg = getNoticeCfg();
		if (cfg == null) {
			cfg = NoticeConfig.init();
		}
		return cfg;
	}

	@Nonnull
	public static NoticeConfig getNoticeCfgOrDefault(@Nullable UserInfo info) {
		return info == null ? NoticeConfig.init() : info.getNoticeCfgOrDefault();
	}

	public void setSwitchCfg(SwitchConfig cfg) {
		this.switchCfg = cfg;
		this.switchConfig = cfg == null ? "" : JSONUtil.encode(cfg);
	}

	public SwitchConfig getSwitchCfg() {
		SwitchConfig cfg = switchCfg;
		if (cfg == null && StringUtil.notEmpty(this.switchConfig)) {
			switchCfg = cfg = JSONUtil.parseObject(this.switchConfig, SwitchConfig.class);
		}
		return cfg;
	}

	public SwitchConfig switchCfgWithInit(WesKit wesKit, Gender gender) {
		SwitchConfig cfg = getSwitchCfg();
		if (cfg == null) {
			cfg = SwitchConfig.init(wesKit, gender);
		}
		return cfg;
	}

	public void setExtendObj(JSONObject extendObj) {
		this.extendObj = extendObj;
		this.extend = JSONUtil.encode(extendObj);
	}

	public JSONObject getExtendObj() {
		if (extendObj == null && StringUtil.notEmpty(extend)) {
			extendObj = JSONUtil.parseObject(extend);
		}
		return extendObj;
	}

	/**
	 * 获取群VIP 权益配置信息
	 *
	 * @param checkValid 是否验证有效性
	 * @return 返回群VIP 规则对象
	 */
	public GroupVipRule getGroupVipConfig(boolean checkValid) {
		// 判断是否在有效期
		if (checkValid && !hasGroupVip()) {
			return null;
		}
		if (this.groupVipRule != null) {
			return this.groupVipRule;
		}
		final JSONObject extObj = getExtendObj();
		if (extObj != null) {
			JSONObject json = extObj.getJSONObject(EXTEND_FIELD);
			if (json != null) {
				this.groupVipRule = json.toJavaObject(GroupVipRule.class);
			}
		}
		return groupVipRule;
	}

	static final ValueFilter emptyToNullFilter = (object, name, value) -> "".equals(value) ? null : value;

	public String serialize() {
		return JSONObject.toJSONString(this, emptyToNullFilter, SerializerFeature.DisableCircularReferenceDetect);
	}

	public static UserInfo deserialize(String json) {
		return JSONUtil.parseObject(json, UserInfo.class);
	}

	public static Map<String, Object> asEmbedInfo(UserInfo info, final User user) {
		return asEmbed(info, t -> CollectionUtil.ofHashMap("id", t.getId(),
				"maritalStatus", ValueProxyImpl.value(t.getMaritalStatus()),
				"maritalStatus_", ValueProxyImpl.label(t.getMaritalStatus()),
				"nationalFlag", user.nationalFlag(),
				"national", user.national(),
				"height", t.getHeight(),
				"weight", t.getWeight(),
				"job", t.getJob(),
				"addr", t.getAddr(),
				"education", ValueProxyImpl.value(t.getEducation()),
				"education_", ValueProxyImpl.label(t.getEducation()),
				"area", t.getArea(),
				"location", t.getLocation(),
				"homeTown", t.getHomeTown(),
				"findTag", t.getFindTag(),
				"findTag_", ValueProxyImpl.label(FindTagType.of(t.getFindTag())),
				"yearIncome", t.getYearIncome(),
				"yearIncome_", YearIncomeType.findName(t.getYearIncome()),
				"industry", t.getIndustry(),
				"industry_", Industry.findName(t.getIndustry()),
				"country", user.defaultCountry().getValue(),
				"slogan", t.getSlogan(),
				"groupVipLevel", t.getGroupVipLevel(),
				"groupVipExpireTime", t.getGroupVipExpireTime(),
				"groupVip", t.hasGroupVip()
		));
	}

	public static Map<String, Object> asEmbedInfo(UserInfo info) {
		return asEmbed(info, t -> CollectionUtil.ofHashMap("id", t.getId(),
				"maritalStatus", ValueProxyImpl.value(t.getMaritalStatus()),
				"maritalStatus_", ValueProxyImpl.label(t.getMaritalStatus()),
				"height", t.getHeight(),
				"weight", t.getWeight(),
				"job", t.getJob(),
				"addr", t.getAddr(),
				"education", ValueProxyImpl.value(t.getEducation()),
				"education_", ValueProxyImpl.label(t.getEducation()),
				"area", t.getArea(),
				"location", t.getLocation(),
				"homeTown", t.getHomeTown(),
				"findTag", t.getFindTag(),
				"findTag_", ValueProxyImpl.label(FindTagType.of(t.getFindTag())),
				"yearIncome", t.getYearIncome(),
				"yearIncome_", YearIncomeType.findName(t.getYearIncome()),
				"industry", t.getIndustry(),
				"industry_", Industry.findName(t.getIndustry()),
				"slogan", t.getSlogan(),
				"findTag_", ValueProxyImpl.label(FindTagType.of(t.getFindTag())),
				"groupVipLevel", t.getGroupVipLevel(),
				"groupVipExpireTime", t.getGroupVipExpireTime(),
				"groupVip", t.hasGroupVip()
		));
	}

	/**
	 * 是否具备有效的群VIP
	 */
	public boolean hasGroupVip() {
		return groupVipExpireTime != null && groupVipExpireTime.getTime() > System.currentTimeMillis();
	}

	public static String USER_ID = "user_id";
	public static String SLOGAN = "slogan";
	public static String GROUP_VIP_EXPIRE_TIME = "group_vip_expire_time";

}
